home *** CD-ROM | disk | FTP | other *** search
/ Die Ultimative Software-P…i Collection 1996 & 1997 / Die Ultimative Software-Pakete CD-ROM fur Atari Collection 1996 & 1997.iso / g / gnu_c / gpplib22.zoo / libsrc / dtoa.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-30  |  7.2 KB  |  341 lines

  1. /* 
  2. Copyright (C) 1990 Free Software Foundation
  3.     written by Doug Lea (dl@rocky.oswego.edu)
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17.  
  18. #ifdef __GNUG__
  19. #pragma implementation
  20. #endif
  21. #include <builtin.h>
  22. #include <math.h>
  23. #include <values.h>
  24. #include <xallocri.h>
  25.  
  26. extern AllocRing _libgxx_fmtq;
  27.  
  28. #ifndef M_LN2
  29. #define M_LN2        0.69314718055994530942
  30. #define M_LN10        2.30258509299404568402
  31. #endif
  32.  
  33. #ifdef __GNUC__ /* cfront cannot compile this routine */
  34. // OBSOLETE ROUTINE!
  35.  
  36. char* dtoa(double fpnum,  char cvt, int width, int prec)
  37. {
  38.   // set up workspace
  39.  
  40.   // max possible digits <= those need to show all of prec + exp
  41.   // <= ceil(log10(HUGE)) plus space for null, etc.
  42.  
  43.   const int worksiz = int((M_LN2 / M_LN10) * DMAXEXP) + 8; 
  44.  
  45.   // for fractional part
  46.   char  fwork[worksiz];
  47.   char* fw = fwork;
  48.  
  49.   // for integer part
  50.   char  iwork[worksiz];
  51.   char* iworkend = &iwork[sizeof(iwork) - 1];
  52.   char* iw = iworkend;
  53.   *iw = 0;
  54.  
  55.   // for exponent part
  56.  
  57.   const int eworksiz = int(M_LN2 * _DEXPLEN) + 8;
  58.   char  ework[eworksiz];
  59.   char* eworkend = &ework[sizeof(ework) - 1];
  60.   char* ew = eworkend;
  61.   *ew = 0;
  62.  
  63. #if (_IEEE != 0) && (!defined(atarist))
  64.   if (isinf(fpnum))
  65.   {
  66.     char* inffmt = (char *) _libgxx_fmtq.alloc(5);
  67.     char* inffmtp = inffmt;
  68.     if (fpnum < 0)
  69.       *inffmtp++ = '-';
  70.     strcpy(inffmtp, "Inf");
  71.     return inffmt;
  72.   }
  73.  
  74.   if (isnan(fpnum))
  75.   {
  76.     char* nanfmt = (char *) _libgxx_fmtq.alloc(4);
  77.     strcpy(nanfmt, "NaN");
  78.     return nanfmt;
  79.   }
  80. #endif
  81.  
  82.   // grab sign & make non-negative
  83.   int is_neg = fpnum < 0;
  84.   if (is_neg) fpnum = -fpnum;
  85.  
  86.   // precision matters
  87.  
  88.   if (prec > worksiz - 2) // can't have more prec than supported
  89.     prec = worksiz - 2;
  90.   
  91.   double powprec;
  92.   if (prec == 6)
  93.     powprec = 1.0e6;
  94.   else
  95.     powprec = pow(10.0, (long) prec);
  96.  
  97.   double rounder = 0.5 / powprec;
  98.  
  99.   int f_fmt = cvt == 'f' ||
  100.     ((cvt == 'g') && (fpnum == 0.0 || (fpnum >= 1e-4 && fpnum < powprec)));
  101.  
  102.   int iwidth = 0;
  103.   int fwidth = 0;
  104.   int ewidth = 0;
  105.  
  106.   if (f_fmt)  // fixed format
  107.   {
  108.     double ipart;
  109.     double fpart = modf(fpnum, &ipart);
  110.  
  111.     // convert fractional part
  112.  
  113.     if (fpart >= rounder || cvt != 'g')
  114.     {
  115.       fpart += rounder;
  116.       if (fpart >= 1.0)
  117.       {
  118.         ipart += 1.0;
  119.         fpart -= 1.0;
  120.       }
  121.       double ffpart = fpart;
  122.       double ifpart;
  123.       for (int i = 0; i < prec; ++i)
  124.       {
  125.         ffpart = modf(ffpart * 10.0, &ifpart);
  126.         *fw++ = '0' + int(ifpart);
  127.         ++fwidth;
  128.       }
  129.       if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
  130.       {
  131.         for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
  132.         {
  133.           *p = 0;
  134.           --fwidth;
  135.         }
  136.       }
  137.     }
  138.  
  139.     // convert integer part
  140.     if (ipart == 0.0)
  141.     {
  142.       if (cvt != 'g' || fwidth < prec || fwidth < width)
  143.       {
  144.         *--iw = '0'; ++iwidth;
  145.       }
  146.     }
  147.     else if (ipart <= double(MAXLONG)) // a useful speedup
  148.     {
  149.       long li = long(ipart);
  150.       while (li != 0)
  151.       {
  152.         *--iw = '0' + (li % 10);
  153.         li = li / 10;
  154.         ++iwidth;
  155.       }
  156.     }
  157.     else // the slow way
  158.     {
  159.       while (ipart > 0.5)
  160.       {
  161.         double ff = modf(ipart / 10.0, &ipart);
  162.         ff = (ff + 0.05) * 10.0;
  163.         *--iw = '0' + int(ff);
  164.         ++iwidth;
  165.       }
  166.     }
  167.  
  168.     // g-fmt: kill part of frac if prec/width exceeded
  169.     if (cvt == 'g')
  170.     {
  171.       int m = prec;
  172.       if (m < width)
  173.         m = width;
  174.       int adj = iwidth + fwidth - m;
  175.       if (adj > fwidth)
  176.         adj = fwidth;
  177.       if (adj > 0)
  178.       {
  179.         for (char* f = &fwork[fwidth-1]; f >= fwork && adj > 0; --adj, --f)
  180.         {
  181.           --fwidth;
  182.           char ch = *f;
  183.           *f = 0;
  184.           if (ch > '5') // properly round: unavoidable propagation
  185.           {
  186.             int carry = 1;
  187.             for (char* p = f - 1; p >= fwork && carry; --p)
  188.             {
  189.               ++*p;
  190.               if (*p > '9')
  191.                 *p = '0';
  192.               else
  193.                 carry = 0;
  194.             }
  195.             if (carry)
  196.             {
  197.               for (p = iworkend - 1; p >= iw && carry; --p)
  198.               {
  199.                 ++*p;
  200.                 if (*p > '9')
  201.                   *p = '0';
  202.                 else
  203.                   carry = 0;
  204.               }
  205.               if (carry)
  206.               {
  207.                 *--iw = '1';
  208.                 ++iwidth;
  209.                 --adj;
  210.               }
  211.             }
  212.           }
  213.         }
  214.       }
  215.     }
  216.               
  217.   }
  218.   else  // e-fmt
  219.   {
  220.     
  221.     // normalize
  222.     int exp = 0;
  223.     while (fpnum >= 10.0)
  224.     {
  225.       fpnum *= 0.1;
  226.       ++exp;
  227.     }
  228.     double almost_one = 1.0 - rounder;
  229.     while (fpnum > 0.0 && fpnum < almost_one)
  230.     {
  231.       fpnum *= 10.0;
  232.       --exp;
  233.     }
  234.     
  235.     double ipart;
  236.     double fpart = modf(fpnum, &ipart);
  237.  
  238.  
  239.     if (cvt == 'g')     // used up one digit for int part...
  240.     {
  241.       --prec;
  242.       powprec /= 10.0;
  243.       rounder = 0.5 / powprec;
  244.     }
  245.  
  246.     // convert fractional part -- almost same as above
  247.     if (fpart >= rounder || cvt != 'g')
  248.     {
  249.       fpart += rounder;
  250.       if (fpart >= 1.0)
  251.       {
  252.         fpart -= 1.0;
  253.         ipart += 1.0;
  254.         if (ipart >= 10.0)
  255.         {
  256.           ++exp;
  257.           ipart /= 10.0;
  258.           fpart /= 10.0;
  259.         }
  260.       }
  261.       double ffpart = fpart;
  262.       double ifpart;
  263.       for (int i = 0; i < prec; ++i)
  264.       {
  265.         ffpart = modf(ffpart * 10.0, &ifpart);
  266.         *fw++ = '0' + int(ifpart);
  267.         ++fwidth;
  268.       }
  269.       if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
  270.       {
  271.         for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
  272.         {
  273.           *p = 0;
  274.           --fwidth;
  275.         }
  276.       }
  277.     }
  278.  
  279.     
  280.     // convert exponent
  281.  
  282.     char eneg = exp < 0;
  283.     if (eneg) exp = - exp;
  284.  
  285.     while (exp > 0)
  286.     {
  287.       *--ew = '0' + (exp % 10);
  288.       exp /= 10;
  289.       ++ewidth;
  290.     }
  291.  
  292.     while (ewidth < 2)  // ensure at least 2 zeroes
  293.     {
  294.       *--ew = '0';
  295.       ++ewidth;
  296.     }
  297.  
  298.     *--ew = eneg ? '-' : '+';
  299.     *--ew = 'e';
  300.  
  301.     ewidth += 2;
  302.  
  303.     // convert the one-digit integer part
  304.     *--iw = '0' + int(ipart);
  305.     ++iwidth;
  306.     
  307.   }
  308.  
  309.   // arrange everything in returned string
  310.  
  311.   int showdot = cvt != 'g' || fwidth > 0;
  312.  
  313.   int fmtwidth = is_neg + iwidth + showdot + fwidth + ewidth;
  314.   
  315.   int pad = width - fmtwidth;
  316.   if (pad < 0) pad = 0;
  317.   
  318.   char* fmtbase = (char *) _libgxx_fmtq.alloc(fmtwidth + pad + 1);
  319.   char* fmt = fmtbase;
  320.   
  321.   for (int i = 0; i < pad; ++i) *fmt++ = ' ';
  322.   
  323.   if (is_neg) *fmt++ = '-';
  324.   
  325.   for (i = 0; i < iwidth; ++i) *fmt++ = *iw++;
  326.   
  327.   if (showdot)
  328.   {
  329.     *fmt++ = '.';
  330.     fw = fwork;
  331.     for (i = 0; i < fwidth; ++i) *fmt++ = *fw++;
  332.   }
  333.   
  334.   for (i = 0; i < ewidth; ++i) *fmt++ = *ew++;
  335.   
  336.   *fmt = 0;
  337.   
  338.   return fmtbase;
  339. }
  340. #endif
  341.